﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace Wwtfly.Utility
{
    /// <summary>
    /// 常用方法
    /// </summary>
    public class MethodHelper {
        /// <summary>
        /// 获得字符串长度，区分单字节和双字节
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns>字符串长度</returns>
        public static int LengthString(string str) {
            byte[] bytes = Encoding.Unicode.GetBytes(str);
            int index = 0, currentLength = 0;
            for (int i = 0; i < bytes.Length; i++) {
                index = (int)(i * 2 + 1);
                if (index > bytes.Length) { break; }
                currentLength += bytes[index] > 0 ? 2 : 1;
            }
            return currentLength;
        }
        /// <summary>
        /// 截取指定长度的字符串，区分单字节和双字节
        /// </summary>
        /// <param name="str">截取的字符串</param>
        /// <param name="length">截取的长度</param>
        /// <returns>指定截取长度后的字符串</returns>
        public static string SubString(string str, int length) {
            int trimLength = length * 2;
            byte[] strByte = Encoding.Unicode.GetBytes(str.Trim());
            if (strByte.Length <= trimLength) { return str; }
            int index = 0, currentLength = 0;
            for (int i = 0; i < length; i++) {
                index = (int)(i * 2 + 1);
                currentLength += strByte[index] > 0 ? 1 : 2;
                if (currentLength >= str.Length) { break; }
            }
            return str.Substring(0, currentLength < str.Length ? currentLength : str.Length);
        }
        /// <summary>
        /// 通过文件扩展名获取文件 ContentType，例：jpg 的 ContentType 为 "image/pjpeg"
        /// </summary>
        /// <param name="extension">扩展名，例：.jpg</param>
        /// <returns>ContentType，例：image/pjpeg)</returns>
        public static string GetContentTypeByExtentsion(string extension) {
            string contentType = string.Empty;
            extension = extension.ToLower();

            SortedList<string, string> fileContents = new SortedList<string, string>();
            fileContents.Add(".bmp", "image/bmp");
            fileContents.Add(".jpg", "image/pjpeg");
            fileContents.Add(".jpe", "image/pjpeg");
            fileContents.Add(".jpeg", "image/pjpeg");
            fileContents.Add(".pdf", "application/pdf");
            fileContents.Add(".png", "image/x-png");
            fileContents.Add(".gif", "image/gif");
            fileContents.Add(".rar", "application/octet-stream");
            fileContents.Add(".7z", "application/octet-stream");
            fileContents.Add(".zip", "application/x-zip-compressed");

            if (fileContents.ContainsKey(extension)) {
                int index = fileContents.IndexOfKey(extension);
                contentType = fileContents.Values[index];
            }

            return contentType;
        }
        /// <summary>
        /// 计算机存储单位转换方法
        /// </summary>
        /// <param name="fileSize">大小，字节</param>
        /// <returns>转换后的文字表示，例：2G，20.02M</returns>
        public static string GetFileSize(int fileSize) {
            string size = string.Empty;
            double threePow = Math.Pow(1024, 3);
            double twoPow = Math.Pow(1024, 2);

            if (fileSize >= threePow) {
                size = Math.Round(fileSize / threePow * 1000 / 1000, 2) + "G";
            }
            if (fileSize >= twoPow && fileSize < threePow) {
                size = Math.Round(fileSize / twoPow * 1000 / 1000, 2) + "M";
            }
            if (fileSize >= 1024 && fileSize < twoPow) {
                size = Math.Round((double)(fileSize / 1024 * 1000 / 1000), 2) + "K";
            }
            if (fileSize >= 0 && fileSize < 1024) {
                size = Math.Round((double)fileSize, 2) + "B";
            }
            return size;
        }
        /// <summary>
        /// 生成不重复的随机数，主要用来做随机数产生的种子
        /// </summary>
        /// <returns>int</returns>
        public static int RandomSeed() {
            int result = 0;
            Byte[] rngByte = new Byte[1];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            for (int i = 0; i < 5; i++) {
                rng.GetBytes(rngByte);
                result += rngByte[0];
            }
            return result;
        }
        /// <summary>
        /// 生成指定长度的随机字符串（包含字母/数字/特殊字符）
        /// </summary>
        /// <param name="length">指定的长度</param>
        /// <returns>字符串</returns>
        public static string RandomString(int length) {
            return RandomString(length, RandomTypeEnum.All);
        }
        /// <summary>
        /// 生成指定长度的随机字符串
        /// </summary>
        /// <param name="length">指定的长度</param>
        /// <param name="randomType">随机码生成的范围</param>
        /// <returns>字符串</returns>
        public static string RandomString(int length, RandomTypeEnum randomType) {
            const string num = "0123456789";
            const string symbol = "~!@#$%^&()_=+{[}];',.";
            const string letter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

            string randomString = string.Empty;
            string returnValue = string.Empty;

            switch (randomType) {
                case RandomTypeEnum.Letter:
                    randomString = letter;
                    break;
                case RandomTypeEnum.LetterAndNum:
                    randomString = letter + num;
                    break;
                case RandomTypeEnum.LetterAndSymbol:
                    randomString = letter + symbol;
                    break;
                case RandomTypeEnum.Num:
                    randomString = num;
                    break;
                case RandomTypeEnum.NumAndSymbol:
                    randomString = num + symbol;
                    break;
                case RandomTypeEnum.Symobl:
                    randomString = symbol;
                    break;
                default:
                    randomString = letter + num + symbol;
                    break;
            }

            for (int i = 0; i < length; i++) {
                returnValue += randomString.Substring(new Random(RandomSeed()).Next(1, randomString.Length), 1);
            }

            return returnValue;
        }
        /// <summary>
        /// 生成指定长度的随机字符串（中文）
        /// </summary>
        /// <param name="length">长度</param>
        /// <returns>中文字符串</returns>
        public static string RandomStringCN(int length) {
            return RandomStringCN(length, string.Empty);
        }
        /// <summary>
        /// 生成指定长度的随机字符串（中文）
        /// </summary>
        /// <param name="length">长度</param>
        /// <param name="specifiedZHChars">汉字集，如果未指定则使用《GB2312简体中文编码表》</param>
        /// <returns>中文字符串</returns>
        public static string RandomStringCN(int length, string specifiedCNChars) {
            string returnValue = string.Empty;

            for (int i = 0; i < length; i++) {
                // 没有提供汉字集，则按照《GB2312简体中文编码表》来选择
                if (string.IsNullOrEmpty(specifiedCNChars)) {
                    byte[] charsByte = new byte[2];
                    // 高字节选择 \0xb0 - \0xf7
                    charsByte[0] = (byte)new Random(RandomSeed()).Next(0xb0, 0xf7);
                    // 低字节选择 \0xa1 - \0xfe
                    charsByte[1] = (byte)new Random(RandomSeed()).Next(0xa1, 0xfe);

                    returnValue += Encoding.GetEncoding("gb2312").GetString(charsByte);
                }
                // 指定了汉字集
                else {
                    returnValue += specifiedCNChars.Substring(
                        new Random(RandomSeed()).Next(1, specifiedCNChars.Length), 1);
                }
            }
            return returnValue;
        }

        #region Enum

        /// <summary>
        /// 获取指定枚举中，对应枚举的 Description 的 Attribute 的值，
        /// 与枚举的索引组成匿名对象加入到 List 中返回，new { Text = text, Value = value }
        /// </summary>
        /// <param name="enumType">指定枚举的 Type</param>
        /// <returns>List</returns>
        public static List<object> GetEnumDescriptionToList(Type enumType) {
            if (enumType.IsEnum) {
                int value;
                string text;
                object[] attr;
                List<object> resultList = new List<object>();
                Type descriptionType = typeof(DescriptionAttribute);

                foreach (FieldInfo fi in enumType.GetFields()) {
                    if (fi.FieldType.IsEnum) {
                        attr = fi.GetCustomAttributes(descriptionType, true);
                        if (attr.Length == 0) {
                            throw new FormatException("enum 类型错误");
                        }
                        text = attr.Length > 0 ? ((DescriptionAttribute)attr[0]).Description : fi.Name;
                        value = (int)enumType.InvokeMember(fi.Name, BindingFlags.GetField, null, null, null);
                        resultList.Add(new { Text = text, Value = value });
                    }
                }
                return resultList;
            }
            else {
                throw new ArgumentException("必须是 enum 类型");
            }
        }
        /// <summary>
        /// 获取指定枚举,
        /// 与枚举的索引组成匿名对象加入到 List 中返回，new { Text = text, Value = value }
        /// </summary>
        /// <param name="enumType">指定枚举的 Type</param>
        /// <returns>List</returns>
        public static List<object> GetEnumToList(Type enumType) {
            if (enumType.IsEnum) {
                int value;
                string text;
                List<object> resultList = new List<object>();

                foreach (FieldInfo fi in enumType.GetFields()) {
                    if (fi.FieldType.IsEnum) {
                        text = fi.Name;
                        value = (int)enumType.InvokeMember(fi.Name, BindingFlags.GetField, null, null, null);
                        resultList.Add(new { Text = text, Value = value });
                    }
                }
                return resultList;
            }
            else {
                throw new ArgumentException("必须是 enum 类型");
            }
        }
        /// <summary>
        /// 根据 value 读取指定枚举中的 Description 的 Attribute 的值，
        /// </summary>
        /// <param name="enumType">指定枚举的 Type</param>
        /// <param name="value">值</param>
        /// <returns>string</returns>
        public static string GetEnumsDescription(Type enumType, int value) {
            if (enumType.IsEnum) {
                int val;
                string text;
                object[] attr;
                Type descriptionType = typeof(DescriptionAttribute);

                foreach (FieldInfo fi in enumType.GetFields()) {
                    if (fi.FieldType.IsEnum) {
                        attr = fi.GetCustomAttributes(descriptionType, true);
                        if (attr.Length == 0) {
                            //throw new FormatException("enum 类型错误");
                            continue;
                        }
                        text = attr.Length > 0 ? ((DescriptionAttribute)attr[0]).Description : fi.Name;
                        val = (int)enumType.InvokeMember(fi.Name, BindingFlags.GetField, null, null, null);
                        if (value == val) {
                            return text;
                        }
                    }
                }
                return string.Empty;
            }
            else {
                throw new ArgumentException("必须是 enum 类型");
            }
        }
        /// <summary>
        /// 通过枚举的名称返回枚举
        /// </summary>
        /// <typeparam name="T">枚举</typeparam>
        /// <param name="name">枚举的名称</param>
        /// <returns>T</returns>
        public static T GetEnumByName<T>(string name)
        {
            Type orderStatusType = typeof(T);
            if (orderStatusType.IsEnum) {
                var result = Enum.Parse(orderStatusType, name, true);
                if (Enum.IsDefined(orderStatusType, result)) {
                    return (T)result;
                }
                else {
                    throw new IndexOutOfRangeException("未找到指定的信息");
                }
            }
            else {
                throw new ArgumentException("必须是 enum 类型");
            }
        }
        /// <summary>
        /// 通过枚举返回单据状态字符串
        /// </summary>
        /// <typeparam name="T">枚举</typeparam>
        /// <param name="enumType">枚举</param>
        /// <returns>string</returns>
        protected string GetNameByEnum<T>(T enumType) {
            if (typeof(T).IsEnum) {
                return Enum.GetName(typeof(T), enumType);
            }
            else {
                throw new ArgumentException("必须是 enum 类型");
            }
        }

        #endregion
    }
}
